<?php

/**
 * Wget Curl驱动核心
 *
 * @author	 jonwang(jonwang@myqee.com)
 * @category   MyQEE
 * @package	System
 * @subpackage Core
 * @copyright  Copyright (c) 2008-2011 myqee.com
 * @license	http://www.myqee.com/license.html
 */
class MyQEE_HttpGet_Driver_Curl
{

    protected $http_data = array();

    protected $agent;

    protected $cookies;

    protected $referer;

    protected $_option = array();
    
    const ERROR_HOST = '请求的URL错误';
    
    const ERROR_GET = 'GET请求错误';
    
    const ERROR_POST = 'POST请求错误';

    function __construct()
    {
    
    }

    /**
     * 设置$cookie
     * @param $agent
     */
    public function set_agent($agent)
    {
        $this->agent = $agent;
    }

    /**
     * 设置$cookie
     * @param string $cookie
     */
    public function set_cookies($cookies)
    {
        $this->cookies = $cookies;
    }

    /**
     * 设置$referer
     * @param string $referer
     */
    public function set_referer($referer)
    {
        $this->referer = $referer;
    }

    public function set_option($key, $value)
    {
        $this->_option[$key] = $value;
    }

    /**
     * 用POST方式提交
     * @param $url
     * @param string/array $vars
     * @param $timeout 超时时间，默认120秒
     * @return string, false on failure
     */
    public function post($url, $vars, $timeout = 60)
    {
        $time = microtime(true);
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_HEADER, true);
        if ( preg_match('#^https://#i', $url) )
        {
            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, true);
            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        }
        curl_setopt($ch, CURLOPT_HTTPHEADER, array('Expect:'));
        if ( $this->cookies )
        {
            curl_setopt($ch, CURLOPT_COOKIE, http_build_query($this->cookies, '', ';'));
        }
        if ( $this->agent )
        {
            curl_setopt($ch, CURLOPT_USERAGENT, $this->agent);
        }
        elseif ( array_key_exists('HTTP_USER_AGENT', $_SERVER) )
        {
            curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
        }
        else
        {
            curl_setopt($ch, CURLOPT_USERAGENT, $this->agent);
        }
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
        curl_setopt($ch, CURLOPT_POST, true);
        if ( is_array($vars) )
        {
            $vars = http_build_query($vars);
        }
        curl_setopt($ch, CURLOPT_POSTFIELDS, $vars);
        foreach ( $this->_option as $k => $v )
        {
            curl_setopt($ch, $k, $v);
        }
        $data = curl_exec($ch);
        
        $this->http_data = $this->get_data($data, $ch);
        
        if ( $this->http_data['code'] != 200 )
        {
            Core::debug()->error(HttpGet_Driver_Curl::ERROR_POST);
            return false;
        }
        
        curl_close($ch);
        
        $this->_option = array();
        return $this->http_data['data'];
    }

    /**
     * GET方式获取数据，支持多个URL
     * 
     * @param string/array $url
     * @param $timeout
     * @return string, false on failure
     */
    public function get($url, $timeout = 10)
    {
        if ( is_array($url) )
        {
            $getone = false;
            $urls = $url;
        }
        else
        {
            $getone = true;
            $urls = array($url);
        }
        
        $data = $this->get_urls($urls, $timeout);
        
        if ( $getone )
        {
            $this->http_data = $this->http_data[$url];
            return $data[$url];
        }
        else
        {
            return $data;
        }
    }

    /**
     * 支持多线程抓取网页
     *
     * @see http://cn.php.net/manual/en/function.curl-multi-exec.php#88772
     * @param Array/string $urls
     * @param Int $timeout
     * @return Array
     */
    protected function get_urls($urls, $timeout = 10)
    {
        $threads = 10; // 线程
        

        $i = 0;
        $threadsRunning = 0;
        $total = count($urls);
        
        $this->http_data = array(); //清空可能的旧数据
        

        $mcurl = curl_multi_init();
        while ( true )
        {
            // Check if done
            if ( $threadsRunning == 0 && $i >= $total )
            {
                # 跑完了
                break;
            }
            
            // Fill up the slots
            while ( $threadsRunning < $threads && $i < $total )
            {
                $url = current($urls); //URL指针移动到下一个
                next($urls);
                $i ++; //计数增加
                $threadsRunning ++; //当前正在运行数增加
                if ( ! $url ) continue;
                
                $ch = curl_init();
                curl_setopt($ch, CURLOPT_URL, $url);
                curl_setopt($ch, CURLOPT_HEADER, true);
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
                
                if ( $this->cookies )
                {
                    curl_setopt($ch, CURLOPT_COOKIE, http_build_query($this->cookies, '', ';'));
                }
                if ( $this->agent )
                {
                    curl_setopt($ch, CURLOPT_USERAGENT, $this->agent);
                }
                elseif ( isset($_SERVER['HTTP_USER_AGENT']) )
                {
                    curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
                }
                if ( $this->_option ) foreach ( $this->_option as $k => $v )
                {
                    curl_setopt($ch, $k, $v);
                }
                
                curl_multi_add_handle($mcurl, $ch);
            }
            
            // Let mcurl do it's thing
            curl_multi_select($mcurl);
            while ( ($mcRes = curl_multi_exec($mcurl, $mcActive)) == CURLM_CALL_MULTI_PERFORM )
            {
                usleep(100000);
            }
            
            if ( $mcRes != CURLM_OK )
            {
                break;
            }
            
            while ( true==($done = curl_multi_info_read($mcurl)) )
            {
                $ch = $done['handle'];
                $done_data = curl_multi_getcontent($ch);
                $done_url = curl_getinfo($ch, CURLINFO_EFFECTIVE_URL);
                $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
                curl_multi_remove_handle($mcurl, $ch);
                
                # 将返回信息放在$this->http_data中
                $this->http_data[$done_url] = $this->get_data($done_data, $ch);
                curl_close($ch);
                
                $threadsRunning --;
                # 返回数据
                $result[$done_url] = $http_code == 200 ? $done_data : false;
            }
        }
        curl_multi_close($mcurl);
        
        return $result;
    }

    public function get_resut_data()
    {
        return $this->http_data;
    }

    protected function get_data($data, $ch)
    {
        $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
        $result['code'] = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $result['data'] = substr($data, $header_size);
        $result['header'] = explode("\r\n", substr($data, 0, $header_size));
        $result['time'] = curl_getinfo($ch, CURLINFO_TOTAL_TIME);
        
        return $result;
    }
}